package edu.rmit.service.impl;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Enumeration;
import java.util.Hashtable;

import edu.rmit.service.IChatCallBackService;
import edu.rmit.service.IChatService;

/**
 * This interface defines the chat operation. Which can implement register a
 * user to the group chat, remove a user from group chat, and send chat message,
 * send forum message, and remove forum message.
 * 
 * @author Joey George
 * @version 1.0
 */
@SuppressWarnings("serial")
public class ChatServiceImpl extends UnicastRemoteObject implements
		IChatService {

	/**
	 * Keeps the chat list of a particular group.
	 */
	private Hashtable<Integer, Hashtable<String, IChatCallBackService>> chatListeners = null;

	/**
	 * Initialize the list which want to keep the chat list.
	 * 
	 * @throws RemoteException
	 */
	public ChatServiceImpl() throws RemoteException {
		chatListeners = new Hashtable<Integer, Hashtable<String, IChatCallBackService>>();
	}

	/**
	 * This method implements the operation to add a user to a particular group
	 * to chat.
	 * 
	 * @param groupId
	 *            The group id which the user want to participant.
	 * @param userName
	 *            The user name of the participant
	 * @param callBackService
	 *            The callback service which can implement to add the message to
	 *            the corresponding control
	 * @return The status whether the user is successfully attended.
	 * @throws RemoteException
	 */
	@Override
	public int addChatListener(int groupId, String userName,
			IChatCallBackService callbackService) throws RemoteException {
		Hashtable<String, IChatCallBackService> callBackServices = chatListeners
				.get(groupId);

		if (callBackServices == null) {
			callBackServices = new Hashtable<String, IChatCallBackService>();
		}
		if (callBackServices.get(userName) != null) {
			return ERR_GROUP_ID;
		} else {
			callBackServices.put(userName, callbackService);
			chatListeners.put(groupId, callBackServices);
			sendChatEvent(JOIN, groupId, userName, SERVER, null);
			return SUCCESS;
		}

	}

	/**
	 * This method implements the operation to remove a user to a particular
	 * group to chat.
	 * 
	 * @param groupId
	 *            The group id which the user want to leave.
	 * @param userName
	 *            The user name of the leave person.
	 * @param reason
	 *            The reason message.
	 * @throws RemoteException
	 */
	@Override
	public void removeChatListener(int groupId, String userName, String reason)
			throws RemoteException {
		sendChatEvent(QUIT, groupId, userName, reason, null);
		Hashtable<String, IChatCallBackService> callBackServices = chatListeners
				.get(groupId);
		callBackServices.remove(userName);
		if (callBackServices.isEmpty()) {
			chatListeners.remove(groupId);
		}
	}

	/**
	 * This method implements the operation to remove an forum message
	 * 
	 * @param groupId
	 *            The group id which the forum message is belongs to.
	 * @param sender
	 *            The sender name which this forum message is been send.
	 * @param messageId
	 *            The message id which you want to delete.
	 * @throws RemoteException
	 */
	@Override
	public void removeForumMessage(int groupId, String sender, int messageId)
			throws RemoteException {
		sendChatEvent(DELETE_FORUM_MSG, groupId, sender, null, messageId);
		String messageWapper = "One forum message has been deleted!";
		sendChatEvent(SYSTEM_IFNO, groupId, sender, messageWapper, null);
	}

	/**
	 * This method implements the operation to send an chat message
	 * 
	 * @param groupId
	 *            The group id which the chat message is belongs to.
	 * @param sender
	 *            The sender name which this chat message is been send.
	 * @param message
	 *            The message which you want to send.
	 * @throws RemoteException
	 */
	@Override
	public void sendChatMessage(int groupId, String sender, String message)
			throws RemoteException {
		sendChatEvent(CHAT_MSG, groupId, sender, message, null);
	}

	/**
	 * This method implements the operation to send an forum message
	 * 
	 * @param groupId
	 *            The group id which the forum message is belongs to.
	 * @param sender
	 *            The sender name which this forum message is been send.
	 * @param message
	 *            The message which you want to send.
	 * @throws RemoteException
	 */
	@Override
	public void sendForumMessage(int groupId, String sender, String message)
			throws RemoteException {
		sendChatEvent(FORUM_MSG, groupId, sender, message, null);
	}

	/**
	 * This method is to implement the send a particular message to the users
	 * which currently in the group.
	 * 
	 * @param type
	 *            The message type.
	 * @param groupId
	 *            The group id which you want to send message.
	 * @param sender
	 *            The message sender's name
	 * @param message
	 *            The message's body.
	 * @param messageId
	 *            The message's id, this will used when you want to delete an
	 *            forum message.
	 * @throws RemoteException
	 */
	@SuppressWarnings("unchecked")
	private void sendChatEvent(int type, int groupId, String sender,
			String message, Integer messageId) throws RemoteException {
		Hashtable<String, Hashtable<String, IChatCallBackService>> chatListenersClone = null;
		synchronized (this) {
			chatListenersClone = (Hashtable<String, Hashtable<String, IChatCallBackService>>) chatListeners
					.clone();
		}
		Hashtable<String, IChatCallBackService> callBackServices = chatListenersClone
				.get(groupId);
		if (sender.equals(SERVER) || callBackServices.get(sender) != null) {
			try {
				for (Enumeration<IChatCallBackService> e = callBackServices
						.elements(); e.hasMoreElements();) {
					IChatCallBackService callBackService = e.nextElement();
					switch (type) {
					case CHAT_MSG:
						callBackService.addChatMessage(sender, message);
						break;
					case FORUM_MSG:
						callBackService.addForumMessage(sender, message);
						break;
					case JOIN:
						callBackService.joinedChatMessage(sender);
						break;
					case QUIT:
						callBackService.quitChatMessage(sender);
						break;
					case DELETE_FORUM_MSG:
						callBackService.removeForumMessage(messageId);
						break;
					case SYSTEM_IFNO:
						callBackService.systemInfoMessage(message);
						break;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
